package com.lds.sign_sdk.interceptor;

import com.lds.sign_sdk.annotation.SignCheck;
import com.lds.sign_sdk.handler.SignDataHandler;
import com.lds.sign_sdk.util.HttpUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lds.sign_sdk.util.MD5Util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Date 2022/1/7
 * @Time 15:27
 * @Author liudongs
 * @E-mail liudongs@aliyun.com
 * @Version 1.0.0
 * @Description
 **/
public class SignAuthInterceptor implements HandlerInterceptor {
    private Logger LOGGER = LoggerFactory.getLogger(SignAuthInterceptor.class);
    private SignDataHandler dataHandler;

    public SignAuthInterceptor(SignDataHandler signDataHandler) {
        this.dataHandler = signDataHandler;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod)handler;
            SignCheck signCheck = (SignCheck)handlerMethod.getMethodAnnotation(SignCheck.class);
            if (signCheck == null) {
                return Boolean.TRUE;
            }

            if (this.dataHandler == null) {
                throw new RuntimeException(" 指定的 SignAuthInterceptor 初始化异常 ");
            }

            String timestampStr = request.getHeader("timestamp");
            if (StringUtils.isBlank(timestampStr)) {
                this.LOGGER.error("timestamp不能为空");
                HttpUtils.render(response, "签名验证失败");
                return Boolean.FALSE;
            }

            String sign = request.getHeader("sign");
            if (StringUtils.isBlank(sign)) {
                this.LOGGER.error("参数sign不能为空");
                HttpUtils.render(response, "签名验证失败");
                return Boolean.FALSE;
            }

            String nonce = request.getHeader("nonce");
            if (StringUtils.isBlank(nonce)) {
                this.LOGGER.error("参数nonce不能为空");
                HttpUtils.render(response, "签名验证失败");
                return Boolean.FALSE;
            }

            long timestamp;
            try {
                timestamp = Long.parseLong(timestampStr);
            } catch (Exception var17) {
                this.LOGGER.error(var17.getMessage(), var17);
                HttpUtils.render(response, "签名验证失败");
                return Boolean.FALSE;
            }

            long timeMillis = System.currentTimeMillis();
            if (Math.abs(timeMillis - timestamp) / 1000L > 180L) {
                this.LOGGER.error("timestamp无效");
                HttpUtils.render(response, "签名验证失败");
                return Boolean.FALSE;
            }

            boolean nonceExists = this.dataHandler.redisHasKey("x-nonce-" + nonce);
            if (nonceExists) {
                this.LOGGER.error("nonce重复");
                HttpUtils.render(response, "签名验证失败");
                return Boolean.FALSE;
            }

            String bodyParamStr = HttpUtils.getBodyString(request);
            if (StringUtils.isEmpty(bodyParamStr)) {
                this.LOGGER.error("body参数为空");
                HttpUtils.render(response, "签名验证失败");
                return Boolean.FALSE;
            }

            Map<String, String> dataMap = new HashMap();
            dataMap.put("nonce", nonce);
            dataMap.put("timestamp", String.valueOf(timestamp));
            dataMap.put("body", bodyParamStr);
            String checkSign = MD5Util.getHmacMD5Signature(dataMap);
            this.LOGGER.info("timestamp:{}, checkSign:{}, timeMillis:{}", new Object[]{timestamp, checkSign, timeMillis});
            if (!sign.equals(checkSign)) {
                this.LOGGER.error("签名验证失败:{}", dataMap.toString());
                HttpUtils.render(response, "签名验证失败");
                return Boolean.FALSE;
            }

            this.dataHandler.redisSet("x-nonce-" + nonce, nonce, 120L, TimeUnit.SECONDS);
        }

        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

